package ru.tests;

import org.apache.commons.lang.time.DateUtils;
import ru.housewife.model.DayMenu;

import javax.xml.transform.Source;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.MessageFormat;
import java.util.*;

/**
 * TODO: add description
 *
 * @author Alexander Troshanin
 */
public class BetterProgrammer {

    private static final int DOUBLES_CNT = 100000;
    private static final int ITER_CNT = 13;

    private static String calcDecimalFormat(double d) {
        DecimalFormat fmt = new DecimalFormat("#.##", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
        return fmt.format(d);
    }

    private static MathContext mctx = new MathContext(3, RoundingMode.DOWN);
    private static String calcBigDecStr(double d) {

//        BigDecimal x = new BigDecimal(23.234, mctx);

        BigDecimal dec = new BigDecimal(d).setScale(2, BigDecimal.ROUND_DOWN);
//        BigDecimal dec = new BigDecimal(d, mctx);
        return dec.toString();
    }

    private static double calcBigDec(double d) {
        BigDecimal dec = new BigDecimal(d).setScale(2, BigDecimal.ROUND_DOWN);
        return dec.doubleValue();
    }

    private static double calcDummy(double d) {
        long i1 = (long) d;
        d = d - i1;
        d = d * 100;
        long i2 = (long) d;
        d = i2;
        d = d / 100;
        d = d + i1;
        return d;
    }

    private static void testBigDecimalStr(double[] doubles) {
        for (int j=0; j<ITER_CNT; j++) {
            for (int i=0; i<doubles.length; i++) {
                calcBigDecStr(doubles[i]);
            }
        }
    }

    private static void testDecimal(double[] doubles) {
        for (int j=0; j<ITER_CNT; j++) {
            for (int i=0; i<doubles.length; i++) {
                calcDecimalFormat(doubles[i]);
            }
        }
    }

    private static double testBigDecimal(double[] doubles) {
        double summ = 0;
        for (int j=0; j<ITER_CNT; j++) {
            for (int i=0; i<doubles.length; i++) {
                summ += calcBigDec(doubles[i]);
            }
        }
        return summ;
    }

    private static double testDummy(double[] doubles) {
        double summ = 0;
        for (int j=0; j<ITER_CNT; j++) {
            for (int i=0; i<doubles.length; i++) {
                summ += calcDummy(doubles[i]);
            }
        }
        return summ;
    }

    private static String [] colnames = {"qwe_1", "qwe_2", "qwe_3", "qwe_4", "qwe_55", "qwe_d1", "qwew_1"};

    private static void getSequencedFieldValue(String seqName) {
        seqName = seqName.toUpperCase();
        for (String columnName : colnames) {
            if (columnName.toUpperCase().startsWith(seqName)) {
                try {
                    System.out.println(Integer.parseInt(columnName.substring(seqName.length())));
                } catch (Exception e) {
                    System.out.println(e.getMessage() + " - " + columnName);
                }
            }
        }
    }


    public static void main(String[] args) {

        getSequencedFieldValue("qwe_");
        getSequencedFieldValue("qwe");
        getSequencedFieldValue("qwew_");

        System.exit(111);

        System.out.println(0 % 2);
        System.out.println(1 % 2);
        System.out.println(0 % 1);
        System.out.println(1 % 1);

        Calendar cal1 = Calendar.getInstance();
        System.out.println(cal1.getTime());
        cal1.add(Calendar.DAY_OF_MONTH, 1);
        System.out.println(cal1.getTime());
        cal1.add(Calendar.DATE, 1);
        System.out.println(cal1.getTime());
        cal1.add(Calendar.DAY_OF_YEAR, 1);
        System.out.println(cal1.getTime());
        cal1.add(Calendar.DAY_OF_WEEK, 1);
        System.out.println(cal1.getTime());


        cal1.get(Calendar.DAY_OF_YEAR);

        Calendar cal2 = Calendar.getInstance();

        //cal2.get()

        //DateUtils.

        MessageFormat frmt0 = new MessageFormat("test {0,date,yyyy-MM-dd} test");

//        Map mp = new HashMap();
//        mp.put("cob")
        String result0 = frmt0.format(new Object[]{new Date()});
        System.out.println(result0);

        String patern1 = "test ${cob,date,yyyy-MM-dd} test";
        patern1 = patern1.replace("${cob,", "{0,");
        MessageFormat frmt1 = new MessageFormat(patern1);

        String result1 = frmt1.format(new Object[]{new Date()});
        System.out.println(result1);

        System.exit(121);


//        for (int t=0; t<10000; t++) {

            Random rnd = new Random();

            double [] doubles = new double[DOUBLES_CNT];
            for (int i=0; i<doubles.length; i++) {
//                doubles[i] = rnd.nextDouble() + 0.9874637;
            doubles[i] = 1.8411793951785225;
            }

/*
        long start1 = System.currentTimeMillis();
            double d1 = testDummy(doubles);
        long finish1 = System.currentTimeMillis();
        long start2 = finish1;
            double d2 = testBigDecimal(doubles);
        long finish2 = System.currentTimeMillis();
*/
        long start1 = System.currentTimeMillis();
        testDecimal(doubles);
        long finish1 = System.currentTimeMillis();
        long start2 = finish1;
        testBigDecimalStr(doubles);
        long finish2 = System.currentTimeMillis();

        System.out.println("      dummy method: " + (finish1 - start1));
        System.out.println("big decimal method: " + (finish2 - start2));
        System.out.println("      dummy method:" + calcDecimalFormat(doubles[0]));
        System.out.println("big decimal method:" + calcBigDecStr(doubles[0]));
//            System.out.println(d1);
//            System.out.println(d2);

//            if (d1 != d2) {
//                System.out.println(doubles[0]);
//                System.out.println("      dummy method:" + calcDummy(doubles[0]));
//                System.out.println("big decimal method:" + calcBigDec(doubles[0]));
//                System.exit(111);
//            }
//        }

        System.exit(111);

        NodeImpl c1 = new NodeImpl(1);
        NodeImpl c11 = new NodeImpl(11);
        NodeImpl c12 = new NodeImpl(12);
        NodeImpl c13 = new NodeImpl(13);

        NodeImpl c111 = new NodeImpl(111);
        NodeImpl c112 = new NodeImpl(112);
        NodeImpl c113 = new NodeImpl(113);

        NodeImpl c211 = new NodeImpl(211);
        NodeImpl c212 = new NodeImpl(212);
        NodeImpl c213 = new NodeImpl(213);

        NodeImpl c311 = new NodeImpl(311);
        NodeImpl c312 = new NodeImpl(312);
        NodeImpl c313 = new NodeImpl(313);

        List<Node> childs1 = new ArrayList<Node>();
        childs1.add(c11);
        childs1.add(c12);
        childs1.add(c13);

        c1.setChilds(childs1);

        List<Node> childs11 = new ArrayList<Node>();
        childs11.add(c111);
        childs11.add(c112);
        childs11.add(c113);
        c11.setChilds(childs11);

        List<Node> childs12 = new ArrayList<Node>();
        childs12.add(c211);
        childs12.add(c212);
        childs12.add(c213);
        c12.setChilds(childs12);

        List<Node> childs13 = new ArrayList<Node>();
        childs13.add(c311);
        childs13.add(c312);
        childs13.add(c313);
        c13.setChilds(childs13);

        List<Node> result = traverseTreeInDepth(c1);

        System.out.println(result);
    }

    // Please do not change this interface
    public static interface Node {
        int getValue();
        List<Node> getChildren();
    }

    public static class NodeImpl implements Node {

        int v;

        List<Node> childs;

        public NodeImpl(int v) {
            this.v = v;
        }

        @Override
        public int getValue() {
            return v;
        }

        @Override
        public List<Node> getChildren() {
            return childs;
        }

        public void setChilds(List<Node> childs) {
            this.childs = childs;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder();
            sb.append("NodeImpl");
            sb.append("{v=").append(v);
            sb.append('}');
            return sb.toString();
        }
    }

    public static List<Node> traverseTreeInDepth(Node root) {
        /*
          Please implement this method to
          traverse the tree in depth and return a list of all passed nodes.

          The method shall work optimally with large trees.
         */

        StackNode stack = new StackNode(root.getChildren().iterator());
        List<Node> nodes = new LinkedList<Node>();
        nodes.add(root);
        do {

            if (stack.value.hasNext()) {
                Node nextChild = stack.value.next();
                nodes.add(nextChild);
                if (nextChild.getChildren() != null && !nextChild.getChildren().isEmpty()) {
                    StackNode nextStack = new StackNode(nextChild.getChildren().iterator());
                    stack.next = nextStack;
                    nextStack.prev = stack;
                    stack = nextStack;
                }
            } else {
                stack = stack.prev;
            }

        } while (stack != null);

        return nodes;
    }

    static class StackNode {
        Iterator<Node> value;
        StackNode next;
        StackNode prev;

        StackNode(Iterator<Node> value) {
            this.value = value;
        }

    }
}

class BetterProgrammerTask {

}



class BetterProgrammerTask0 {

    public static Object[] reverseArray(Object[] a) {
        /*
          Please implement this method to
          return a new array where the order of elements has been reversed from the original
          array.
         */
        if (a == null || a.length < 2) {
            return a;
        }
        for (int i = 0; i < a.length / 2; i++) {
            Object q = a[i];
            a[i] = a[(a.length - 1) - i];
            a[(a.length - 1) - i] = q;
        }
        return a;
    }
}

class BetterProgrammerTask1 {

    public static String getBinaryRepresentation(int n) {
        /*
         Please implement this method to
         return a String with the binary representation of any number n, where n >= 0.
         Example: "101" is a binary representation of 5
        */
        return Integer.toBinaryString(n);
    }
}

class BetterProgrammerTask111 {

    // Please do not change this interface

    interface ListNode {
        int getItem();

        ListNode getNext();

        void setNext(ListNode next);
    }

    public static ListNode reverse(ListNode node) {
        /*
          Please implement this method to
          reverse a given linked list.
         */
        if (node == null) {
            return null;
        }

        int listLength = 1;

        ListNode nextNode = node;
        while (nextNode.getNext() != null) {
            listLength++;
            nextNode = nextNode.getNext();
        }
        ListNode lastNode = nextNode;

        if (listLength < 2) {
            return node;
        }

        int curNodeIndx = 0;
        ListNode curNode = node;
        do {

            ListNode targetNode = curNode;
            int indx2 = curNodeIndx;
            do {
                targetNode = targetNode.getNext();
                indx2++;
            } while (indx2 < (listLength - 1) - curNodeIndx);

            nextNode = curNode.getNext();

            ListNode q = curNode.getNext();
            curNode.setNext(targetNode.getNext());
            targetNode.setNext(q);

            curNode = nextNode;
            curNodeIndx++;
        } while (curNodeIndx < listLength / 2);

        return lastNode;
    }


    static class ListNodeImpl implements ListNode {

        int item;
        ListNode next;

        ListNodeImpl(int item) {
            this.item = item;
        }

        @Override
        public int getItem() {
            return item;  //To change body of implemented methods use File | Settings | File Templates.
        }

        @Override
        public ListNode getNext() {
            return next;  //To change body of implemented methods use File | Settings | File Templates.
        }

        @Override
        public void setNext(ListNode next) {
            this.next = next;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder();
            sb.append("ListNodeImpl");
            sb.append("{item=").append(item);
            sb.append('}');
            return sb.toString();
        }
    }

}


class BetterProgrammerTask2 {

    // Please do not change this interface

    interface ListNode {
        int getItem();

        ListNode getNext();

        void setNext(ListNode next);
    }

    public static ListNode reverse(ListNode node) {
        /*
          Please implement this method to
          reverse a given linked list.
         */

        ListNode curNode = node;
        ListNode nextNode = node.getNext();
        ListNode prevNode = null;
        ListNode prevPrevNode = null;
        while (curNode.getNext() != null) {
            nextNode = curNode.getNext();
            if (prevNode != null) {
                prevNode.setNext(prevPrevNode);
            }
            prevPrevNode = prevNode;
            prevNode = curNode;
            curNode = nextNode;
        }
        if (prevNode != null) {
            prevNode.setNext(prevPrevNode);
        }
        curNode.setNext(prevNode);

        return nextNode;
    }


    static class ListNodeImpl implements ListNode {

        int item;
        ListNode next;

        ListNodeImpl(int item) {
            this.item = item;
        }

        @Override
        public int getItem() {
            return item;  //To change body of implemented methods use File | Settings | File Templates.
        }

        @Override
        public ListNode getNext() {
            return next;  //To change body of implemented methods use File | Settings | File Templates.
        }

        @Override
        public void setNext(ListNode next) {
            this.next = next;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder();
            sb.append("ListNodeImpl");
            sb.append("{item=").append(item);
            sb.append('}');
            return sb.toString();
        }
    }

}

class BetterProgrammerTask3 {



    public void doMeth() {

        while (true) {

            char [] str = new char[6];
            for (int j =0; j<6; j++) {
//                str[j] =
            }
        }



    }

}


class Change {
    private final int _dollars;
    private final int _quarters; //25 cents
    private final int _dimes; // 10 cents
    private final int _nickels; // 5 cents
    private final int _cents; // 1 cent


    public Change(int dollars, int quarters, int dimes, int nickels, int cents) {
        _dollars = dollars;
        _quarters = quarters;
        _dimes = dimes;
        _nickels = nickels;
        _cents = cents;
    }


    public int getDollars() {
        return _dollars;
    }


    public int getQuarters() {
        return _quarters;
    }


    public int getDimes() {
        return _dimes;
    }


    public int getNickels() {
        return _nickels;
    }


    public int getCents() {
        return _cents;
    }
}
